/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.orogeny.properties;

import com.softwarecraftsmen.orogeny.annotations.InternalApi;
import com.softwarecraftsmen.orogeny.buildEnvironments.BuildEnvironment;
import static com.softwarecraftsmen.orogeny.properties.PropertyNamePrefix.fromName;
import static com.softwarecraftsmen.orogeny.properties.PropertyNamePrefix.system;
import static com.softwarecraftsmen.orogeny.properties.PropertyNamePrefix.environment;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static java.lang.String.format;
import static java.util.Locale.UK;

public class PropertyName implements Evaluatable, Comparable<PropertyName>
{
	@NotNull
	public static final PropertyName EnvironmentPATH = environment.property("PATH");

	@NotNull
	public static final PropertyName EnvironmentCLASSPATH = environment.property("CLASSPATH");

	@NotNull
	public static final PropertyName EnvironmentHOME = environment.property("HOME");

	@NotNull
	public static final PropertyName EnvironmentJAVA_HOME = environment.property("JAVA_HOME");

	@NotNull
	public static final PropertyName EnvironmentMANPATH = environment.property("MANPATH");

	@NotNull
	public static final PropertyName EnvironmentPWD = environment.property("PWD");

	@NotNull
	public static final PropertyName EnvironmentOLDPWD = environment.property("OLDPWD");

	@NotNull
	public static final PropertyName EnvironmentTMPDIR = environment.property("TMPDIR");

	@NotNull
	public static final PropertyName EnvironmentUSER = environment.property("USER");

	@NotNull
	public static final PropertyName EnvironmentSHELL = environment.property("SHELL");

	@NotNull
	public static final PropertyName EnvironmentBASH = environment.property("BASH");

	@NotNull
	public static final PropertyName EnvironmentIFS = environment.property("IFS");

	@NotNull
	public static final PropertyName EnvironmentDISPLAY = environment.property("DISPLAY");

	@NotNull
	public static final PropertyName SystemFileEncoding = system.property("file.encoding");

	@NotNull
	public static final PropertyName SystemLineSeparator = system.property("line.separator");

	@NotNull
	public static final PropertyName SystemFileSeparator = system.property("file.separator");

	@NotNull
	public static final PropertyName SystemPathSeparator = system.property("path.separator");

	@NotNull
	public static final PropertyName SystemJavaClassPath = system.property("java.class.path");

	@NotNull
	public static final PropertyName SystemJavaClassVersion = system.property("java.class.version");

	@NotNull
	public static final PropertyName SystemJavaEndorsedDirs = system.property("java.endorsed.dirs");

	@NotNull
	public static final PropertyName SystemJavaExtDirs = system.property("java.ext.dirs");

	@NotNull
	public static final PropertyName SystemJavaHome = system.property("java.home");

	@NotNull
	public static final PropertyName SystemJavaTmpDir = system.property("java.io.tmpdir");

	@NotNull
	public static final PropertyName SystemJavaLibraryPath = system.property("java.library.path");

	@NotNull
	public static final PropertyName SystemJavaVersion = system.property("java.version");

	@NotNull
	public static final PropertyName SystemJavaRuntimeName = system.property("java.runtime.name");

	@NotNull
	public static final PropertyName SystemJavaRuntimeVersion = system.property("java.runtime.version");

	@NotNull
	public static final PropertyName SystemJavaVendor = system.property("java.vendor");

	@NotNull
	public static final PropertyName SystemJavaVendorUrl = system.property("java.vendor.url");

	@NotNull
	public static final PropertyName SystemJavaVendorUrlBug = system.property("java.vendor.url.bug");

	@NotNull
	public static final PropertyName SystemJavaSpecificationName = system.property("java.specification.name");

	@NotNull
	public static final PropertyName SystemJavaSpecificationVendor = system.property("java.specification.vendor");

	@NotNull
	public static final PropertyName SystemJavaSpecificationVersion = system.property("java.specification.version");

	@NotNull
	public static final PropertyName SystemJavaVmInfo = system.property("java.vm.info");

	@NotNull
	public static final PropertyName SystemJavaVmName = system.property("java.vm.name");

	@NotNull
	public static final PropertyName SystemJavaVmVendor = system.property("java.vm.vendor");

	@NotNull
	public static final PropertyName SystemJavaVmVersion = system.property("java.vm.version");

	@NotNull
	public static final PropertyName SystemJavaVmSpecificationName = system.property("java.vm.specification.name");

	@NotNull
	public static final PropertyName SystemJavaVmSpecificationVendor = system.property("java.vm.specification.vendor");

	@NotNull
	public static final PropertyName SystemJavaVmSpecificationVersion = system.property("java.vm.specification.version");

	@NotNull
	public static final PropertyName SystemOsArch = system.property("os.arch");

	@NotNull
	public static final PropertyName SystemOsName = system.property("os.name");

	@NotNull
	public static final PropertyName SystemOsVersion = system.property("os.version");

	@NotNull
	public static final PropertyName SystemUserDir = system.property("user.dir");

	@NotNull
	public static final PropertyName SystemUserHome = system.property("user.home");

	@NotNull
	public static final PropertyName SystemUserLanguage = system.property("user.language");

	@NotNull
	public static final PropertyName SystemUserName = system.property("user.name");

	@NotNull
	public static final PropertyName SystemUserTimezone = system.property("user.timezone");

	private final PropertyNamePrefix prefix;
	private final String unprefixedName;

	PropertyName(final @NotNull PropertyNamePrefix prefix, final @NotNull String unprefixedName)
	{
		this.prefix = prefix;
		this.unprefixedName = unprefixedName;
	}

	@NotNull
	public static PropertyName propertyName(final @NotNull String prefixedName)
	{
		final int index = prefixedName.indexOf(":");
		return new PropertyName(fromName(prefixedName, index), prefixedName.substring(index + 1));
	}

	@NotNull
	public String toString()
	{
		return format(UK, "%1$s:%2$s", prefix, unprefixedName);
	}

	public boolean equals(final @Nullable Object o)
	{
		if (this == o)
		{
			return true;
		}
		if (o == null || getClass() != o.getClass())
		{
			return false;
		}

		final PropertyName that = (PropertyName) o;

		return prefix.equals(that.prefix) && unprefixedName.equals(that.unprefixedName);
	}

	public int hashCode()
	{
		int result;
		result = prefix.hashCode();
		result = 31 * result + unprefixedName.hashCode();
		return result;
	}

	//TODO: Hide from public API
	@InternalApi
	@NotNull
	public String evaluate(final @NotNull BuildEnvironment buildEnvironment)
	{
		return buildEnvironment.getProperty(this).evaluate(buildEnvironment);
	}

	//TODO: Hide from public API
	@InternalApi
	public boolean isDynamic()
	{
		return prefix.isDynamic();
	}

	public int compareTo(final @NotNull PropertyName that)
	{
		final int compareTo = this.prefix.compareTo(that.prefix);
		if (compareTo != 0)
		{
			return compareTo;
		}
		return this.unprefixedName.compareTo(that.unprefixedName);
	}
}
